package com.mzj.saas.mservice.smartlock.service.yaluete;

import com.alibaba.fastjson.JSON;
import com.mzj.saas.commons.enums.LockAlarmTypeEnum;
import com.mzj.saas.mservice.lock.Repository.*;
import com.mzj.saas.mservice.lock.entity.*;
import com.mzj.saas.mservice.smartlock.vo.yaluete.YltCallBackVO;
import com.mzj.saas.mservice.smartlock.vo.yaluete.YltPushContentVO;
import com.mzj.saas.redis.RedisService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 亚略特-智能锁事件处理
 *
 * @author shun
 * @createDate: 2021年9月16日 下午7:27:12
 * @version: 1.0
 */
@Service
public class SmarkLockYltEventHandleService {

    private static final Logger log = LoggerFactory.getLogger(SmarkLockYltEventHandleService.class);
    private static final String authSql = "SELECT a.id AS lockAuthId,a.author_user_id as userId,a.user_name as userName  FROM saas_smart_lock_auth a "
            + "LEFT  JOIN  saas_smart_lock_pwd p ON a.id = p.lock_auth_id \n"
            + "WHERE  a.lock_id = ? AND p.f_app_user_id  = ?";

    private static final String cardSql = "SELECT a.id AS lockAuthId,a.author_user_id as userId,a.user_name AS userName FROM saas_smart_lock_auth a LEFT JOIN "
            + "saas_smart_lock_card c ON a.id = c.lock_auth_id WHERE a.lock_id = ? AND c.f_app_user_id = ?";

    private static final String fingerprintSql = "SELECT a.id AS lockAuthId,a.author_user_id as userId,a.user_name AS userName FROM saas_smart_lock_auth a LEFT JOIN "
            + "saas_smart_lock_fingerprint f ON a.id = f.lock_auth_id WHERE a.lock_id = ? AND f.f_app_user_id = ?";

    private static final String bleSql = "SELECT a.id AS lockAuthId,a.author_user_id as userId,a.user_name AS userName FROM saas_smart_lock_auth a LEFT JOIN "
            + "saas_smart_lock_ble c ON a.id = c.lock_auth_id WHERE a.lock_id = ? AND c.f_app_user_id = ?";

    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private SmartLockRepository smartLockRepository;
    @Autowired
    private LockFrozenSetRepository lockFrozenSetRepository;
    @Autowired
    private LockOpenLogRepository lockOpenLogRepository;
    @Autowired
    private RedisService redisService;
    @Autowired
    private LockAlarmRepository lockAlarmRepository;
    @Autowired
    private SmartLockEmpowerRepository smartLockEmpowerRepository;

    /**
     * 开锁日志事件处理
     */
    public void logEventHandle(YltCallBackVO cvo) {
        log.info("亚略特, 锁日志  vo={}", JSON.toJSONString(cvo));
        try {
            List<String> macList = cvo.getPushContent().stream().map(c -> c.getfLockMAC()).distinct()
                    .collect(Collectors.toList());
            List<SmartLock> lockList = smartLockRepository.findBySnIn(macList);

            Map<String, SmartLock> lockMap = lockList.stream()
                    .collect(Collectors.toMap(SmartLock::getSn, smartLock -> smartLock));
            List<LockOpenLog> logList = new ArrayList<>();
            for (YltPushContentVO vo : cvo.getPushContent()) {
                SmartLock lock = lockMap.get(vo.getfLockMAC());
                if (lock == null) {
                    log.warn("亚略特, 数据库未找到设备信息, deviceId={}", vo.getfLockMAC());
                    continue;
                }
                // 开门记录
                LockOpenLog openLog = new LockOpenLog();
                try {
                    Integer passType = getOpenWay(vo.getfOpenWay());

                    openLog.setLockId(lock.getId());
                    openLog.setHouseId(lock.getHouseId());
                    openLog.setOpenMode(passType);
                    // 亚略特 124开锁编码 = 内开
                    openLog.setOpenType(vo.getfOpenWay() == 124 ? 2 : 1);// 开门类型：0未知
                    // 1外开门
                    // 2内开门
                    openLog.setBuildName(lock.getBuildName());
                    openLog.setCommunityName(lock.getCommunityName());
                    openLog.setUnitName(lock.getUnitName());
                    openLog.setMatchUserName(lock.getMatchUserName());
                    openLog.setRoomNumber(lock.getRoomNumber());
                    openLog.setOpenTime(vo.getfStorageTime());
                    openLog.setUserProperty(0);// 开门人性质：0未知 1承租人 2同住人

                    log.info("开锁日志，vo={}", JSON.toJSONString(vo));
                    // 0普通密码 5次数密码
                    if (passType == 0 || passType == 5) {
                        smartLockPwd(openLog, vo.getfLockMAC(), lock.getMatchUserId(), vo.getfUserID());
                    } else if (passType == 1) { // 1动态密码
                    } else if (passType == 11) { // 11普通卡
                        smartLockCard(openLog, vo.getfLockMAC(), lock.getMatchUserId(), vo.getfUserID());
                    } else if (passType == 21) { // 21指纹
                        smartLockFingerprint(openLog, vo.getfLockMAC(), lock.getMatchUserId(), vo.getfUserID());
                    } else if (passType == 25) { // 25蓝牙
                        smartLockBle(openLog, vo.getfLockMAC(), lock.getMatchUserId(), vo.getfUserID());
                    }
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }

                if (openLog.getOpenUserName()!=null && StringUtils.isNotEmpty(openLog.getOpenUserName())){
                    logList.add(openLog);
                }
            }
            lockOpenLogRepository.saveAll(logList);
        } catch (Exception e) {
            log.error("亚略特, 开锁日志事件处理异常" + e.getMessage(), e);
        }
    }

    /**
     * 门锁心跳
     */
    public void lockOnlineCallBack(YltCallBackVO cvo) {
        log.info("亚略特, 门锁心跳  vo={}", JSON.toJSONString(cvo));
        try {
            List<String> macList = cvo.getPushContent().stream().map(c -> c.getfLockMAC()).distinct()
                    .collect(Collectors.toList());
            List<SmartLock> lockList = smartLockRepository.findBySnIn(macList);
            Map<String, SmartLock> lockMap = lockList.stream()
                    .collect(Collectors.toMap(SmartLock::getSn, smartLock -> smartLock));

            List<SmartLock> locks = new ArrayList<>();
            for (YltPushContentVO vo : cvo.getPushContent()) {
                SmartLock lock = lockMap.get(vo.getfLockMAC());
                if (lock == null) {
                    log.warn("亚略特, 数据库未找到设备信息, deviceId={}", vo.getfLockMAC());
                    return;
                }
                log.info("亚略特, 门锁心跳 , 缓存状态={}", lock.getMac());
                // 缓存锁心跳状态
                redisService.putLockheartbeatStatusRedis(lock.getMac(), 130);

                lock.setOnlineStatus(vo.getfStatus() == null || vo.getfStatus() == 2 ? 0 : vo.getfStatus());
                //电量
                BigDecimal fBatVol = new BigDecimal(vo.getfBatVol()).divide(new BigDecimal("10"));
                Integer electricQuantity = 0;
                if (fBatVol.compareTo(new BigDecimal("6")) > -1) {
                    electricQuantity = 100;
                } else if (fBatVol.compareTo(new BigDecimal("4.4")) < 1) {
                    electricQuantity = 0;
                } else {
                    electricQuantity = fBatVol.subtract(new BigDecimal("4.4")).divide(new BigDecimal("1.6"), 2, RoundingMode.HALF_UP).
                            multiply(new BigDecimal("100")).intValue();
                }
                lock.setElectricQuantity(electricQuantity);

                locks.add(lock);
            }

            smartLockRepository.saveAll(locks);
        } catch (Exception e) {
            log.error("亚略特, 门锁心跳 处理异常" + e.getMessage(), e);
        }
    }

    /**
     * 门锁告警日志
     */
    public void lockAlarm(YltCallBackVO cvo) {
        log.info("亚略特, 门锁告警日志  cvo={}", JSON.toJSONString(cvo));
        try {
            List<String> macList = cvo.getPushContent().stream().map(c -> c.getfLockMAC()).distinct()
                    .collect(Collectors.toList());
            List<SmartLock> lockList = smartLockRepository.findBySnIn(macList);
            Map<String, SmartLock> lockMap = lockList.stream()
                    .collect(Collectors.toMap(SmartLock::getSn, smartLock -> smartLock));

            for (YltPushContentVO vo : cvo.getPushContent()) {
                SmartLock lock = lockMap.get(vo.getfLockMAC());
                if (lock == null) {
                    log.warn("亚略特, 数据库未找到设备信息, deviceId={}", vo.getfLockMAC());
                    return;
                }
                // 告警事件处理
                if (vo.getfEvent() != null) {
                    alarmEventHanding(vo, lock);
                }
            }

        } catch (Exception e) {
            log.error("亚略特, 门锁告警日志处理异常" + e.getMessage(), e);
        }
    }

    /**
     * 密码开门记录
     */
    private void smartLockPwd(LockOpenLog lock, String sn, String matchUserId, String fUserId) {

        List<Map<String, Object>> lockAuthList = jdbcTemplate.queryForList(authSql, lock.getLockId(), fUserId);

        if (CollectionUtils.isEmpty(lockAuthList)) {
            log.warn("亚略特, 密码开锁日志事件处理, 未找到相关开门人信息 sn={},lockId={},pwdIndexNum={}", sn, lock.getLockId(), fUserId);
            return;
        }
        Map<String, Object> authMap = lockAuthList.get(0);
        Long lockAuthId = Long.parseLong(authMap.get("lockAuthId").toString());
        String userId = authMap.get("userId") == null?null:authMap.get("userId").toString();
        if (userId != null && matchUserId != null && matchUserId.equals(userId)) {
            lock.setUserProperty(1);
        } else {
            lock.setUserProperty(2);
        }
        String userName = authMap.get("userName").toString();
        lock.setLockAuditId(lockAuthId);
        lock.setUserId(lockAuthId);
        lock.setOpenUserName(StringUtils.isEmpty(userName) ? userName(fUserId):userName);
    }

    /**
     * 指纹开门记录
     */
    private void smartLockFingerprint(LockOpenLog lock, String sn, String matchUserId, String fUserId) {
        List<Map<String, Object>> lockAuthList = jdbcTemplate.queryForList(fingerprintSql, lock.getLockId(), fUserId);
        if (CollectionUtils.isEmpty(lockAuthList)) {
            log.warn("亚略特, 指纹开锁日志事件处理, 未找到相关开门人信息 sn={}, lockId={}, fingerprintIndexNum={}", sn, lock.getLockId(),
                    fUserId);
            return;
        }
        Map<String, Object> authMap = lockAuthList.get(0);
        Long lockAuthId = Long.parseLong(authMap.get("lockAuthId").toString());
        String userId = authMap.get("userId") == null?null:authMap.get("userId").toString();
        if (userId != null && matchUserId != null && matchUserId.equals(userId)) {
            lock.setUserProperty(1);
        } else {
            lock.setUserProperty(2);
        }
        String userName = authMap.get("userName").toString();
        lock.setLockAuditId(lockAuthId);
        lock.setUserId(lockAuthId);
        lock.setOpenUserName(StringUtils.isEmpty(userName) ? userName(fUserId):userName);
    }

    /**
     * 卡开门记录
     */
    public void smartLockCard(LockOpenLog lock, String sn, String matchUserId, String fUserId) {

        List<Map<String, Object>> lockAuthList = jdbcTemplate.queryForList(cardSql, lock.getLockId(), fUserId);
        if (CollectionUtils.isEmpty(lockAuthList)) {
            log.warn("亚略特, 卡开锁日志事件处理, 未找到相关开门人信息 sn={}, lockId={}, pwdIndexNum={}", sn, lock.getLockId(), fUserId);
            return;
        }
        Map<String, Object> authMap = lockAuthList.get(0);
        Long lockAuthId = Long.parseLong(authMap.get("lockAuthId").toString());
        String userId = authMap.get("userId").toString();
        if (matchUserId != null && matchUserId.equals(userId)) {
            lock.setUserProperty(1);
        } else {
            lock.setUserProperty(2);
        }
        String userName = authMap.get("userName").toString();
        lock.setLockAuditId(lockAuthId);
        lock.setUserId(lockAuthId);
        lock.setOpenUserName(StringUtils.isEmpty(userName) ? userName(fUserId):userName);
    }

    /**
     * 蓝牙
     */
    public void smartLockBle(LockOpenLog lock, String sn, String matchUserId, String fUserId) {

        List<Map<String, Object>> lockAuthList = jdbcTemplate.queryForList(bleSql, lock.getLockId(), fUserId);
        if (CollectionUtils.isEmpty(lockAuthList)) {
            log.warn("亚略特, 蓝牙开锁日志事件处理, 未找到相关开门人信息 sn={}, lockId={}, pwdIndexNum={}", sn, lock.getLockId(), fUserId);
            return;
        }
        Map<String, Object> authMap = lockAuthList.get(0);
        Long lockAuthId = Long.parseLong(authMap.get("lockAuthId").toString());
        String userId = authMap.get("userId") == null?null:authMap.get("userId").toString();
        if (userId != null && matchUserId != null && matchUserId.equals(userId)) {
            lock.setUserProperty(1);
        } else {
            lock.setUserProperty(2);
        }
        String userName = authMap.get("userName").toString();
        lock.setLockAuditId(lockAuthId);
        lock.setUserId(lockAuthId);
        lock.setOpenUserName(StringUtils.isEmpty(userName) ? userName(fUserId):userName);
    }

    /**
     * 开发方式转换
     *
     * @param fOpenWay
     * @return
     * @author shun
     * @date 2021年9月16日
     */
    public Integer getOpenWay(Integer fOpenWay) {
        // 0普通密码 1动态密码 5次数密码 9管理员密码 10一键开门 11普通卡 21指纹 25蓝牙 30钥匙 32人脸 33虹膜
        switch (fOpenWay + "") {
            case "1":
                return 21;
            case "2":
                return 0;
            case "4":
                return 11;
            case "8":
                return 25;
            case "16":
                return 32;
            case "32":
                return 33;
            case "64":
                return 30;
            case "125":
                return 1;
            default:
                return 0;
        }
    }

    /**
     * 告警事件处理
     *
     * @param vo
     * @param lock
     * @return
     * @author shun
     * @date 2021年9月17日
     */
    public String alarmEventHanding(YltPushContentVO vo, SmartLock lock) {
        LockAlarm lockAlarm = new LockAlarm();
        switch (vo.getfEvent() + "") {
            case "0":// 重启
                return null;
            case "1":// 低电压 = 低电量
                lockAlarm.setAlarmType(LockAlarmTypeEnum.LOW.getValue());
                lockAlarm.setLockId(lock.getId());
                lockAlarm.setHouseId(lock.getHouseId());
                lockAlarm.setSn(lock.getSn());
                lockAlarm.setElectric(lock.getElectricQuantity());
                lockAlarm.setAlarmTime(new Date());
                lockAlarmRepository.save(lockAlarm);

                return "success";
            case "2":// 设备被拆除 = 防撬
                lockAlarm.setAlarmType(LockAlarmTypeEnum.PICK_PROOF.getValue());
                lockAlarm.setLockId(lock.getId());
                lockAlarm.setHouseId(lock.getHouseId());
                lockAlarm.setSn(lock.getSn());
                lockAlarm.setElectric(lock.getElectricQuantity());
                lockAlarm.setAlarmTime(new Date());
                lockAlarmRepository.save(lockAlarm);

                return "success";
            case "4":// 陌生人尝试开锁
                /**
                 * 查询saas_lock_house_setting表，获取设置信息，如果有设置，才处理
                 */
                LockFrozenSet lockSet = lockFrozenSetRepository.findByLockId(lock.getId());
                if (lockSet == null) {
                    log.info("亚略特, 陌生人开锁告警, 锁未开启告警设置, 过滤, lockid={}", lock.getId());
                    return null;
                }

                lockAlarm.setAlarmType(LockAlarmTypeEnum.STRANGER.getValue());
                lockAlarm.setLockId(lock.getId());
                lockAlarm.setHouseId(lock.getHouseId());
                lockAlarm.setSn(lock.getSn());
                lockAlarm.setElectric(lock.getElectricQuantity());
                lockAlarm.setAlarmTime(new Date());
                lockAlarmRepository.save(lockAlarm);

                return "success";
            case "8":// *高电压(暂未使用)
                return null;
            case "16":// 上电/重启
                return null;
            case "32":// 硬件错误
                return null;
            case "64":// 门未关
                return null;
            case "65":// *门已关
                return null;
            case "66":// *钥匙未拔(暂未使用)
                return null;
            case "67":// *钥匙拔出(暂未使用)
                return null;
            case "68":// 反锁关闭
                return null;
            case "69":// 反锁开启
                return null;
            case "80":// 触发同步
                return null;
            case "81":// 解码成功
                return null;
            case "82":// 解码失败
                return null;
            case "83":// 添加指纹
                return null;
            default:
                return null;
        }
    }

    public String  userName(String fUserId) {
        List<SmartLockEmpower> lockEmpower = smartLockEmpowerRepository.findByFAppUserId(fUserId);
        if (!lockEmpower.isEmpty()){
            return lockEmpower.get(0).getUserName();
        }
        return null;
    }
}
